package com.netty.handler;

import com.alibaba.fastjson.JSON;
import com.netty.constant.Constants;
import com.netty.model.Message;
import com.netty.service.ConnectService;
import com.netty.service.MessageService;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.springframework.stereotype.Component;

import java.util.List;

import static io.netty.buffer.Unpooled.wrappedBuffer;

/**
 * @author suzhen
 * @create 2018/7/11
 */
@Component
public class SocketChannelHandler extends ChannelInitializer<SocketChannel> {

    private MessageService messageService;

    private ConnectService connectService;

    public SocketChannelHandler() {
    }

    public SocketChannelHandler(MessageService messageService, ConnectService connectService) {
        this.messageService = messageService;
        this.connectService = connectService;
    }

    @Override
    protected void initChannel(SocketChannel ch) {
        ChannelPipeline pipeline = ch.pipeline();
        //解决解决半包读问题
        //pipeline.addLast(new LineBasedFrameDecoder(1024));
        //pipeline.addLast(new StringDecoder());
        // HTTP请求的解码和编码
        pipeline.addLast(new HttpServerCodec());
        // 把多个消息转换为一个单一的FullHttpRequest或是FullHttpResponse，
        // 原因是HTTP解码器会在每个HTTP消息中生成多个消息对象HttpRequest/HttpResponse,HttpContent,LastHttpContent
        pipeline.addLast(new HttpObjectAggregator(65536));
        // 主要用于处理大数据流，比如一个1G大小的文件如果你直接传输肯定会撑暴jvm内存的; 增加之后就不用考虑这个问题了
        //向客户端发送HTML5文件
        pipeline.addLast(new ChunkedWriteHandler());
        // 业务代码
        // 协议包长度限制。定义socke请求路径
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws", null, true, Constants.ImserverConfig.MAX_FRAME_LENGTH));

        // 协议包解码
        pipeline.addLast(new MessageToMessageDecoder<WebSocketFrame>() {
            @Override
            protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List<Object> objects) {
                if (frame instanceof TextWebSocketFrame) {
                    String request = ((TextWebSocketFrame) frame).text();
                    Message message = JSON.parseObject(request, Message.class);
                    objects.add(message);
                }
            }
        });
        //输出编码,netty只会输出 WebSocketFrame格式数据
        pipeline.addLast(new MessageToMessageEncoder<Message>() {
            @Override
            protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> out) {
                ByteBuf byteBuf;
                byteBuf = wrappedBuffer(JSON.toJSONBytes(msg));
                WebSocketFrame frame = new TextWebSocketFrame(byteBuf);
                out.add(frame);
            }
        });
        //pipeline.addLast(new ThouthHandler());
        pipeline.addLast(new MessageRequestHandler(messageService, connectService));
    }
}
